home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d14
/
atre12.arc
/
ATREEDLL.ARC
/
ATREE.C
next >
Wrap
C/C++ Source or Header
|
1991-07-27
|
71KB
|
2,096 lines
/*****************************************************************************
**** ****
**** atree.c ****
**** ****
**** Copyright (C) A. Dwelly and W.W. Armstrong, 1990. ****
**** ****
**** All rights reserved. ****
**** ****
**** This is the program file for the "research" version of the adaptive ****
**** logic network package based on work done by Prof. W. W. Armstrong ****
**** and others in the Department of Computing Science, University of ****
**** Alberta, and previous work at the Universite de Montreal, and at ****
**** AT&T Bell Laboratories, Holmdel, N. J. The software demonstrates ****
**** that networks consisting of many layers of linear threshold ****
**** elements can indeed be effectively trained. ****
**** ****
**** License: ****
**** A royalty-free license is granted for the use of this software for ****
**** NON-COMMERCIAL PURPOSES ONLY. The software may be copied and ****
**** modified provided this notice appears in its entirety and unchanged ****
**** in all copies, whether changed or not. Persons modifying the code ****
**** are requested to state the date, the changes made and who made them ****
**** in the modification history. ****
**** ****
**** Warranty: ****
**** No warranty of any kind is provided with this software. ****
**** This software is not supported. Neither the authors, nor the ****
**** University of Alberta, its officers, agents, servants or employees ****
**** shall be liable or responsible in any way for any damage to ****
**** property or direct personal or consequential injury of any nature ****
**** whatsoever that may be suffered or sustained by any licensee, user ****
**** or any other party as a consequence of the use or disposition of ****
**** this software. ****
**** ****
**** Patent: ****
**** The use of a digital circuit which transmits a signal indicating ****
**** heuristic responsibility is protected by U. S. Patent 3,934,231 ****
**** and others assigned to Dendronic Decisions Limited of Edmonton, ****
**** W. W. Armstrong, President. ****
**** ****
**** A royalty-free license is granted for the use of this patent to ****
**** run this software for NON-COMMERCIAL PURPOSES ONLY and the ****
**** extension of this patent license to modified versions of this ****
**** software is granted provided the purpose is NON-COMMERCIAL ONLY. ****
**** ****
**** Modification history: ****
**** ****
**** 90.09.05 Initial implementation, A.Dwelly ****
**** 91.04.15 Port to PC and minor bug fixes, R. Manderscheid ****
**** 91.05.31 Port to Windows & Windows Extensions, M. Thomas ****
**** ****
*****************************************************************************/
#pragma inline
/*****************************************************************************
**** ****
**** Include Files ****
**** ****
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "atree.h"
#define assert(exp)\
{\
if (!(exp))\
{\
char szBuffer[30]; \
wsprintf(szBuffer, "%s, Line %d",\
__FILE__, __LINE__);\
MessageBox (NULL, szBuffer, "Assertion Failed",\
MB_OK | MB_ICONSTOP);\
}\
}
/*****************************************************************************
**** ****
**** Constants ****
**** ****
*****************************************************************************/
#define AND 0
#define RIGHT 1
#define LEFT 2
#define OR 3
#define TRUE 1 /* As usual */
#define FALSE 0
#define UNEVALUATED 2 /* We complete the lattice of boolean functions */
#define ATREE_ERROR -1 /* Don't want conflict with Windows.h ERROR */
#define BOTTOM UNEVALUATED /* Synonyms */
#define TOP ATREE_ERROR
#define LEFTLEAF 0xF0 /* masks for leaf_flag and cmp_flag */
#define RIGHTLEAF 0x0F
#define MAX_RETRY 50 /* No. of retrys before an error in atree_rand_walk */
/* Initialisation values */
#define MAXSET 63
#define ABOVEMID 32
#define BELOWMID 31
#define MINSET 0
/* memory manager constants */
#define SEGLENGTH 65536L /* 64K */
#define NUMSEGS 64 /* can manage up to 4096K */
/*
* Tricky Macros
*/
#define Printf(str,fmt) {\
char string[] = str; \
wsprintf(szBuffer,string,fmt);\
}
/* Public and private procedures */
#define public
#define private static
/* Infinite loops - for EVER */
#define EVER (;;)
/* Printing out the boolean lattice */
#define PRINTBOOL(b) if (b == TRUE) {Printf("1",0);} else if (b == FALSE)\
{Printf("0",0);} else if (b == UNEVALUATED) {Printf("U",0);} else \
if (b == ATREE_ERROR) {Printf("E",0);} else {Printf("?",0);}
/* Verbosity */
#define VERBOSE(level,s) if (verbosity >= level) {s ;}
/* Byte size in bits.*/
#define BYTE (sizeof(char)*8)
/* Tree evaluation macros */
#define EVAL(slf,side) ( (slf & (tree -> leaf_flag)) ? \
( (slf & (tree -> cmp_flag)) ? \
!bv_extract(tree -> side.leaf,vec): \
bv_extract(tree -> side.leaf,vec) ) : \
atree_eval(tree -> side.child,vec) )
#define LEFTEVAL (tree -> sig_left = EVAL(LEFTLEAF,left))
#define RIGHTEVAL (tree -> sig_right = EVAL(RIGHTLEAF,right))
/*
* Types
*/
typedef int bool; /*
* Only TRUE, FALSE, UNEVALUATED or ATREE_ERROR
* are used in these variables
*/
/*
* some static variables needed by the atree memory manager
*/
/* HANDLE to each segment */
static HANDLE seg[NUMSEGS];
/* memory free in each segment */
static WORD freemem[NUMSEGS];
/*
* Preliminary Private Procedure Declarations
*/
private void NEAR PASCAL WinMem_Init();
private LPATREE NEAR PASCAL build_tree(LPINT, char far *,int,int,LPATREE);
private void NEAR PASCAL print_tree(LPATREE, int, int, int);
private bool NEAR PASCAL train(LPATREE, LPBIT_VEC, bool);
private void NEAR PASCAL adapt(LPATREE, LPBIT_VEC, bool);
private char NEAR PASCAL node_function(LPATREE);
/*
* LibMain Procedure to initialize DLL
*/
#pragma argsused
long FAR PASCAL VerbosityWndProc(HWND, WORD, WORD, LONG);
HANDLE hInst;
char szVerbLine1[60];
char szVerbLine2[60];
short cyChar;
int FAR PASCAL LibMain (HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
{
WNDCLASS wndclass;
hInst = hInstance;
wndclass.style = CS_NOCLOSE;
wndclass.lpfnWndProc = VerbosityWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, "atreeico");
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "VERBOSITY";
RegisterClass(&wndclass);
if (wHeapSize > 0)
UnlockData(0);
return 1;
}
long FAR PASCAL VerbosityWndProc(HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
static short cxChar, cxCaps;
char szBuffer[10];
HDC hdc;
short i;
PAINTSTRUCT ps;
TEXTMETRIC tm;
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC(hwnd,hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
TextOut (hdc, 5 * cxChar, cyChar * 6, szVerbLine1, lstrlen(szVerbLine1));
TextOut (hdc, 5 * cxChar, cyChar * 7, szVerbLine2, lstrlen(szVerbLine2));
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
/* PostQuitMessage(0);*/
return 0;
}
return DefWindowProc(hwnd,message, wParam, lParam);
}
/*****************************************************************************
*****************************************************************************
**** ****
**** Public Routines ****
**** ****
*****************************************************************************
*****************************************************************************/
/*****************************************************************************
**** ****
**** void FAR PASCAL atree_init() ****
**** ****
**** Synopsis: ****
**** ****
**** Initialises various global variables, and makes an initial call to ****
**** the random number seed routine. Checks to make sure Windows is in ****
**** protect mode. ****
**** ****
*****************************************************************************/
public void FAR PASCAL
atree_init()
{
DWORD c;
c = GetTickCount();
(void) srand((int) c);
c = GetWinFlags();
if (!(c & WF_PMODE))
{
MessageBox(NULL, "Atree software cannot run\nin Windows Real Mode!",
"Not in Protected Mode!", MB_OK | MB_ICONSTOP);
exit(0);
}
}
/*****************************************************************************
**** ****
**** LPBIT_VEC atree_rand_walk(num,width,p) ****
**** ****
**** int num; ****
**** int width; ****
**** int p; ****
**** ****
**** Synopsis: ****
**** ****
**** Creates an array of _num_ binary vectors, of _width_ bits where ****
**** each is _p_ bits away from its neighbours in Hamming space. Each ****
**** vector is unique. ****
**** This routine returns NULL if it's unable to find enough vectors. ****
*****************************************************************************/
#pragma warn -pia
public LPBIT_VEC FAR PASCAL
atree_rand_walk(num,width,p)
int num;
int width;
int p;
{
/*
* An initial vector is produced with random bits, and each subsequent
* vector in the random walk just has _p_ bits flipped. In order to
* guarantee that each vector is unique, it is checked against
* a chained list of vectors of the same bit sum. If it is not already
* in the chain it is appended to the end, or else the vector is discarded
* and the process repeats itself.
*/
LPBIT_VEC bv_set; /* An array of bit vectors */
LPBIT_VEC pckd_vec; /* The packed unique ? vector */
bool unique; /* Uniqueness flag set during testing */
LPINT bit_sum_chain; /* Pointers to vectors of equivalent bit sums */
LPINT next_vec; /* Chain array */
LPSTR unpckd_vec; /* An unpacked vector */
LPSTR this_vec; /* An unpacked vector */
LPSTR mark_vec; /* TRUE where a bit has been flipped */
int i;
int j;
int old_bit_sum; /* Last number of TRUE bits in vector */
int bit_sum; /* Current number of TRUE bits in vector */
int retrys; /* Number of attempts to find a unique vec */
int victim; /* The bit just twiddled */
int current_vec; /* Part of the chain */
assert(num > 0);
assert(width > 0);
assert(p != 0);
assert(p <= width);
/* Assign space in memory */
bv_set = (LPBIT_VEC) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) num * sizeof(bit_vec));
MEMCHECK(bv_set);
bit_sum_chain = (LPINT) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) (width+1) * sizeof(int));
MEMCHECK(bit_sum_chain);
next_vec = (LPINT) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) num * sizeof(int));
MEMCHECK(next_vec);
unpckd_vec = (LPSTR) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) width * sizeof(char));
MEMCHECK(unpckd_vec);
this_vec = (LPSTR) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) width * sizeof(char));
MEMCHECK(this_vec);
mark_vec = (LPSTR) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) width * sizeof(char));
MEMCHECK(mark_vec);
/* Clear bit_sum_chain */
for (i = 0; i <= width; i++)
{
bit_sum_chain[i] = -1;
}
/* Clear next_vec */
for (i = 0; i < num; i++)
{
next_vec[i] = -1;
}
/* Create initial vector and bit sum */
old_bit_sum = 0;
for (i = 0; i < width; i++)
{
if (unpckd_vec[i] = RANDOM(2))
{
old_bit_sum++;
}
}
bv_set[0] = *(bv_pack(unpckd_vec,width));
bit_sum_chain[old_bit_sum] = 0;
/* Random walk */
for (i = 1; i < num; i++)
{
/* allow multitasking */
Windows_Interrupt(1000);
retrys = 0;
unique = FALSE;
while ((!unique) && (retrys < MAX_RETRY))
{
retrys++;
/* Make a new vector */
bit_sum = old_bit_sum;
for (j = 0; j < width; j++)
{
this_vec[j] = unpckd_vec[j];
mark_vec[j] = FALSE;
}
for (j = 0; j < p; j++)
{
do
{
victim = RANDOM(width);
}
while (mark_vec[victim]);
mark_vec[victim] = TRUE;
this_vec[victim] = !this_vec[victim];
if (this_vec[victim] == FALSE)
{
bit_sum--;
}
else
{
bit_sum++;
}
}
pckd_vec = bv_pack(this_vec,width);
/* Compare it with the existing ones of equal bit length */
if (bit_sum_chain[bit_sum] == -1)
{
/* There are no other vectors with this bit sum, so ... */
unique = TRUE;
bv_set[i] = *pckd_vec;
bit_sum_chain[bit_sum] = i;
next_vec[i] = -1;
}
else
{
current_vec = bit_sum_chain[bit_sum];
for EVER /* We break out of here inside the loop */
{
if (bv_equal(&(bv_set[current_vec]),pckd_vec))
{
/* This vector already exists, unique = FALSE; */
break;
}
else
{
if (next_vec[current_vec] == -1)
{
unique = TRUE;
bv_set[i] = *pckd_vec;
next_vec[current_vec] = i;
next_vec[i] = -1;
break;
}
else
{
current_vec = next_vec[current_vec];
}
}
} /* for EVER */
} /* if (bit_sum_chain...) */
} /* while ((!unique... ))*/
/*
* If Unique is TRUE at this point, we have a unique
* vector stored, we have to set up old_bit sum and unpckd_vec
* for the next vector.
* If unique is FALSE, we have tried to create a unique vector
* MAX_RETRY times, and failed. We therefore signal an error.
*/
if (unique)
{
for (j = 0; j < width; j++)
{
unpckd_vec[j] = this_vec[j];
}
old_bit_sum = bit_sum;
}
else
{
error("random walk failed");
}
} /* for */
/* Free space in memory */
WinMem_Free((LPSTR)bit_sum_chain);
WinMem_Free((LPSTR)next_vec);
WinMem_Free((LPSTR)unpckd_vec);
WinMem_Free((LPSTR)this_vec);
WinMem_Free((LPSTR)mark_vec);
/* Return final vector */
return(bv_set);
}
#pragma warn .pia
/*****************************************************************************
**** ****
**** LPATREE atree_create(numvars,leaves) ****
**** ****
**** int numvars; ****
**** int leaves; ****
**** ****
**** Synopsis: ****
**** ****
**** Creates an Armstrong tree with _leaves_ number of leaves connected ****
**** to _numvars_ variables and their complements. The number of ****
**** leaves should probably be at least twice _numvars_. ****
**** The node functions and the connections are picked at random. ****
**** ****
*****************************************************************************/
public LPATREE FAR PASCAL
atree_create(numvars,leaves)
int numvars;
int leaves;
{
LPATREE tree;
LPINT connection;
char far *complemented;
char comp;
int numvarscount;
int a;
int b;
int tmpi;
char tmpb;
int i;
assert(leaves > 2);
assert(numvars > 0);
/* Assign the memory to hold first part of tree, place as low in memory as possible */
if ((leaves - 1) >= (SEGLENGTH / sizeof(atree)))
tree = (LPATREE) GlobalWire(GlobalAlloc(GMEM_MOVEABLE,(DWORD)SEGLENGTH));
else
tree = (LPATREE) GlobalWire(GlobalAlloc(GMEM_MOVEABLE,((DWORD)leaves - 1) * sizeof(atree)));
MEMCHECK(tree);
/*
* Create a list of bit inputs and shuffle, complemented inputs
* are marked with a TRUE in the complemented array.
*/
connection = (LPINT) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) sizeof(int) * leaves);
MEMCHECK(connection);
complemented = (char far *) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) sizeof(int) * leaves);
MEMCHECK(complemented);
comp = 0x00;
for (i = 0; i < leaves; i++)
{
numvarscount = i % numvars;
if (numvarscount == 0)
{
comp = ~(comp);
}
connection[i] = numvarscount;
complemented[i] = comp;
}
/* Shuffle */
for (i = 0; i < leaves; i++)
{
a = RANDOM(leaves);
b = RANDOM(leaves);
tmpi = connection[a];
connection[a] = connection[b];
connection[b] = tmpi;
tmpb = complemented[a];
complemented[a] = complemented[b];
complemented[b] = tmpb;
}
/* Build tree */
(void) build_tree(connection,complemented,0,leaves - 1,tree);
/*
/* Free memory */
WinMem_Free((LPSTR)connection);
WinMem_Free((LPSTR)complemented);
/* Return results */
return(tree);
}
/*****************************************************************************
**** ****
**** BOOL atree_eval(tree,vec) ****
**** ****
**** LPATREE tree; ****
**** LPBIT_VEC vec; ****
**** ****
**** Synopsis: ****
**** ****
**** Applies the _tree_ to the bit vector _vec_ and returns the result, ****
**** 1 for true, and 0 for false. ****
*****************************************************************************/
#pragma warn -pia
public BOOL FAR PASCAL
atree_eval(tree,vec)
LPATREE tree;
LPBIT_VEC vec;
{
bool result;
/*
* We recursively work our way down the tree.
* Since the && and || operators in C are lazy,
* we automatically get the parsimony (ugly word) that we
* want.
*/
switch (tree -> function)
{
case AND:
tree -> sig_right = UNEVALUATED;
result = LEFTEVAL && RIGHTEVAL;
break;
case RIGHT:
tree -> sig_left = UNEVALUATED;
result = RIGHTEVAL;
break;
case LEFT:
tree -> sig_right = UNEVALUATED;
result = LEFTEVAL;
break;
case OR:
tree -> sig_right = UNEVALUATED;
result = LEFTEVAL || RIGHTEVAL;
break;
}
return(result);
}
#pragma warn .pia
/*****************************************************************************
**** ****
**** BOOL atree_train(tree,tset,correct_result,bit_col,tset_size, ****
**** no_correct,epochs,verbosity) ****
**** ****
**** LPATREE tree; ****
**** LPBIT_VEC tset; ****
**** LPBIT_VEC correct_result; ****
**** int bit_col; ****
**** int tset_size; ****
**** int no_correct; ****
**** int epochs; ****
**** int verbosity; ****
**** ****
**** Synopsis: ****
**** ****
**** This routine is the heart of the library. It takes an atree _tree_ ****
**** to be trained, an array of input vectors _tset_, an array of ****
**** vectors, _correct_result_ where each bit column holds a correct bit ****
**** result for each vector in _tset_. [Note: Only a single vector is ****
**** actually required here, but doing it this way make life convenient ****
**** for training collections of trees for real numbers] An integer ****
**** _bit_col_ denoting the column to be trained on. Another integer ****
**** _test_size gives the size of both the _tset_ and _correct_result_ ****
**** arrays. ****
**** ****
**** The _tree_ is trained until the number of vectors presented in ****
**** _tset_ equals _epoch_ epochs, or the last presentation of the number****
**** in an epoch had at least _no_correct_ presentations. ****
**** The _verbosity_ is currently 0 or 1. ****
**** The routine returns TRUE if it stopped because it succeeded ****
**** _no_correct_ times. ****
**** ****
*****************************************************************************/
public BOOL FAR PASCAL
atree_train(tree,tset,correct_result,bit_col,tset_size,no_correct,
epochs,verbosity)
LPATREE tree;
LPBIT_VEC tset;
LPBIT_VEC correct_result;
int bit_col;
int tset_size;
int no_correct;
int epochs;
int verbosity;
{
bool no_correct_flag = FALSE;
int i;
int j;
int cor_this_epoch;
int vec_num;
LPBIT_VEC vec;
char szBuff[60];
HWND hwnd;
/* For the specified number of epochs */
VERBOSE(1, hwnd = CreateWindow("VERBOSITY", "atree Training Progress",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
250, 180,
NULL, NULL, hInst, NULL);
lstrcpy(szVerbLine1, "Beginning Training...");
lstrcpy(szVerbLine2, " ");
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd)
);
for (i = 0; i < epochs; i++)
{
cor_this_epoch = 0;
VERBOSE(1,wsprintf(szBuff,"Epoch : %d ",i));
/* For the elements of the test set */
for (j = 0; j < tset_size; j++)
{
/* Pick a random vector */
vec_num = RANDOM(tset_size);
vec = tset + vec_num;
/* allow for multitasking */
Windows_Interrupt(1000);
/* Train the tree */
if (train(tree,vec,(bool)bv_extract(bit_col,correct_result + vec_num)))
{
/* The tree succeeded */
cor_this_epoch++;
if (cor_this_epoch == no_correct)
{
no_correct_flag = TRUE;
break; /* out of this epoch */
} /* if (cor_this...) */
} /* if (train..) */
} /* for (j = ..) */
VERBOSE(1,wsprintf(szVerbLine2,"Number correct was %d ",cor_this_epoch);
lstrcpy(szVerbLine1, szBuff);
ScrollWindow(hwnd, 0, -2 * cyChar, NULL, NULL);
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
);
/* If no_correct_flag is TRUE here, its time to stop */
if (no_correct_flag)
{
break; /* out of the epoch loop */
}
} /* for (i = ...) */
/*VERBOSE(1, DestroyWindow(hwnd));*/
return(no_correct_flag);
}
/*****************************************************************************
**** ****
**** (void) atree_print(tree,verbosity) ****
**** ****
**** LPATREE tree; ****
**** ****
**** Synopsis: ****
**** ****
**** Prints out a tree for diagnostic and explanation purposes, the ****
**** verbosity levels are 0 or above. Currently, the Windows ****
**** implementation outputs to a file called atree.out in the current ****
**** directory. ****
*****************************************************************************/
public void FAR PASCAL
atree_print(tree,verbosity)
LPATREE tree;
int verbosity;
{
/*
* This routine makes an call to the private
* print tree routine that takes an extra paramater
* controlling the indentation
*/
int hOut; /* File Handle */
if((hOut = _lcreat("atree.out", 0)) == -1)
{
MessageBox(NULL, "Cannot open ATREE.OUT", "atree_print", MB_OK);
return;
}
print_tree(tree,0,verbosity, hOut);
_lclose(hOut);
}
/*****************************************************************************
**** ****
**** void atree_free(tree) ****
**** ****
**** LPATREE tree; ****
**** ****
**** Synopsis: ****
**** ****
**** Frees the memory used by _tree_ ****
*****************************************************************************/
public void FAR PASCAL
atree_free(tree)
LPATREE tree;
{
if (!(LEFTLEAF & (tree -> leaf_flag)))
atree_free(tree -> left.child);
if (!(RIGHTLEAF & (tree -> leaf_flag)))
atree_free(tree -> right.child);
if (tree -> seg_flag)
GlobalFree(GlobalHandle(HIWORD(tree)));
return;
}
/*****************************************************************************
**** ****
**** (int) atree_load(tree,name) ****
**** ****
**** LPATREE tree; ****
**** LPSTR name; ****
**** ****
**** Synopsis: ****
**** ****
**** Loads a previously stored tree from disk, errors signalled with a ****
**** -1. ****
*****************************************************************************/
/*****************************************************************************
**** ****
**** (int) atree_store(tree,name) ****
**** ****
**** LPATREE tree; ****
**** LPSTR name; ****
**** ****
**** Synopsis: ****
**** ****
**** Writes the _tree_ to disk with filename _name_. Errors are ****
**** signalled with a -1. ****
*****************************************************************************/
/*****************************************************************************
**** ****
**** LPBIT_VEC bv_create(length) ****
**** ****
**** int length; ****
**** ****
**** Synopsis: ****
**** ****
**** Produces a vector of _length_ bits, each one of which has been set ****
**** to 0 ****
*****************************************************************************/
public LPBIT_VEC FAR PASCAL
bv_create(length)
int length;
{
int i;
LPBIT_VEC out_vec;
assert(length > 0);
out_vec = (LPBIT_VEC)WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned)sizeof(bit_vec));
MEMCHECK(out_vec);
out_vec -> len = length;
out_vec -> bv = WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) (length + BYTE - 1) / BYTE);
MEMCHECK(out_vec -> bv);
for (i = 0; i < (length + BYTE - 1) / BYTE; i++)
{
*((out_vec -> bv) + i) = (char) 0;
}
return(out_vec);
}
/*****************************************************************************
**** ****
**** LPBIT_VEC bv_pack(unpacked,length) ****
**** ****
**** LPSTR unpacked; ****
**** int length; ****
**** ****
**** This routine takes an array _arr_ of zero and one characters ****
**** and returns a packed bit vector suitable for use with the other ****
**** routines in this library. ****
*****************************************************************************/
public LPBIT_VEC FAR PASCAL
bv_pack(unpacked,length)
LPSTR unpacked;
int length;
{
LPBIT_VEC out_vec;
LPSTR out_ptr;
int i;
int j;
int bitptr;
/* Create the structure */
out_vec = (LPBIT_VEC) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(bit_vec));
MEMCHECK(out_vec);
out_vec -> len = length;
out_vec -> bv = WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) (length + BYTE - 1) / BYTE);
MEMCHECK(out_vec -> bv);
/* Pack the vector */
out_ptr = out_vec -> bv;
bitptr = 0;
for (i = 0; i < (length + BYTE - 1) / BYTE; i++)
{
*out_ptr = 0;
for (j = 0; j < BYTE; j++)
{
if (bitptr < length)
{
*out_ptr |= (unpacked[bitptr] << j);
bitptr++;
}
else
{
break;
}
}
out_ptr++;
}
/* Return the vector */
return(out_vec);
}
/*****************************************************************************
**** ****
**** int bv_diff(v1,v2) ****
**** ****
**** LPBIT_VEC v1; ****
**** LPBIT_VEC v2; ****
**** ****
**** This function returns the number of bits that are unequal in the ****
**** two vectors. They must be the same number of bits in each vector ****
*****************************************************************************/
public int FAR PASCAL
bv_diff(v1,v2)
LPBIT_VEC v1;
LPBIT_VEC v2;
{
int diff = 0;
int i;
assert (v1 -> len == v2 -> len);
for (i = 0; i < v1 -> len; i++)
{
if (bv_extract(i,v1) != bv_extract(i,v2))
{
diff++;
}
}
return(diff);
}
/*****************************************************************************
**** ****
**** LPBIT_VEC bv_concat(n,vectors) ****
**** ****
**** int n; ****
**** LPBIT_VEC *vectors; ****
**** ****
**** Synopsis: ****
**** ****
**** Returns the bit vector which is the string concatenation of each ****
**** bit vector in _vector_; _n_ is the number of elements in _vector_. ****
*****************************************************************************/
public LPBIT_VEC FAR PASCAL
bv_concat(n,vector)
int n;
LPBIT_VEC FAR *vector;
{
int size;
LPBIT_VEC out_vec;
LPSTR str;
int i;
int j;
int count;
/* Work out how big the new vector will be */
size = 0;
for (i = 0; i < n; i++)
{
size += vector[i] -> len;
}
/* Unpack the input vectors */
str = WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) size);
MEMCHECK(str);
count = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < vector[i] -> len; j++)
{
str[count] = bv_extract(j,vector[i]);
count++;
}
}
out_vec = bv_pack(str,size);
WinMem_Free(str);
return(out_vec);
}
/*****************************************************************************
**** ****
**** LPBIT_VEC bv_copy(vector) ****
**** ****
**** LPBIT_VEC vector; ****
**** ****
**** Synopsis: ****
**** ****
**** Returns a copy of the bit vector _vector_. ****
*****************************************************************************/
public LPBIT_VEC FAR PASCAL
bv_copy(vector)
LPBIT_VEC vector;
{
LPBIT_VEC out_vec;
int i;
/* Work out how big the new vector will be */
out_vec = (LPBIT_VEC) WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(bit_vec));
MEMCHECK(out_vec);
out_vec -> len = vector -> len;
out_vec -> bv = WinMem_Malloc(LMEM_MOVEABLE | LMEM_ZEROINIT, (unsigned) (vector -> len + BYTE - 1) / BYTE);
MEMCHECK(out_vec -> bv);
for (i = 0; i < (vector -> len + BYTE - 1) / BYTE; i++)
{
out_vec -> bv[i] = vector -> bv[i];
}
return(out_vec);
}
/*****************************************************************************
**** ****
**** void bv_set(n,vec,bit) ****
**** ****
**** int n; ****
**** LPBIT_VEC vec; ****
**** BOOL bit; ****
**** ****
**** Synopsis: ****
**** ****
**** Sets bit _n_ in _vec_ to have the value in _bit_. ****
*****************************************************************************/
public void FAR PASCAL
bv_set(n,vec,bit)
int n;
LPBIT_VEC vec;
BOOL bit;
{
char mask;
LPSTR b;
assert(n < vec -> len);
mask = 0x1;
b = (vec -> bv) + ((int) (n / BYTE));
if (bit)
{
*b |= (mask << (n % BYTE));
}
else
{
*b &= ~(mask << (n % BYTE));
}
}
/*****************************************************************************
**** ****
**** BOOL bv_extract(n,vec) ****
**** ****
**** int n; ****
**** LPBIT_VEC vec; ****
**** ****
**** Synopsis: ****
**** ****
**** Returns the _n_th bit of _vec_. ****
*****************************************************************************/
public BOOL FAR PASCAL
bv_extract(n,vec)
int n;
LPBIT_VEC vec;
{
register int mask = 0x1;
assert(n < vec -> len);
return(((*((vec -> bv) + ((int) (n / BYTE)))) & (mask << (n % BYTE))) != 0);
}
/*****************************************************************************
**** ****
**** void bv_print(stream, vector) ****
**** ****
**** FILE *vector; ****
**** LPBIT_VEC vector; ****
**** ****
**** Synopsis: ****
**** ****
**** Prints out _vector_ in binary, MSB is the rightmost. ****
*****************************************************************************/
public void FAR PASCAL
bv_print(stream, vector)
FILE *stream;
LPBIT_VEC vector;
{
LPSTR ptr; /* Points to the current char */
char mask;
int bits; /* Counts the number of bits output */
int i;
bits = 0;
for (ptr = (vector -> bv);
(ptr != (vector -> bv) + (int) ((vector -> len / BYTE) + 1)) &&
(bits < vector -> len); ptr++)
{
mask = 0x1;
for (i = 0; i < BYTE; i++)
{
if ((*ptr & mask) != 0)
{
(void) fprintf(stream, "1");
}
else
{
(void) fprintf(stream, "0");
}
bits++;
if (bits == vector -> len)
{
break;
}
mask <<= 1;
}
}
}
/*****************************************************************************
**** ****
**** void bv_free(vector) ****
**** ****
**** LPBIT_VEC vector; ****
**** ****
**** Synopsis: ****
**** ****
**** Frees the memory used by _vector_ ****
*****************************************************************************/
public void FAR PASCAL
bv_free(vector)
LPBIT_VEC vector;
{
WinMem_Free(vector -> bv);
WinMem_Free((LPSTR) vector);
}
/*****************************************************************************
**** ****
**** BOOL bv_equal(v1,v2) ****
**** ****
**** LPBIT_VEC v1; ****
**** LPBIT_VEC v2; ****
**** ****
**** Synopsis: ****
**** ****
**** Returns TRUE if each bit in v1 and v2 have the same value in the ****
**** same position. It returns FALSE otherwise. ****
*****************************************************************************/
public BOOL FAR PASCAL
bv_equal(v1,v2)
LPBIT_VEC v1;
LPBIT_VEC v2;
{
bool eq;
int i;
eq = TRUE;
if (v1 -> len != v2 -> len)
{
eq = FALSE;
}
else
{
for (i = 0; i < (v1 -> len + BYTE - 1) / BYTE; i++)
{
if (v1 -> bv[i] != v2 -> bv[i])
{
eq = FALSE;
break;
}
}
}
return(eq);
}
/*****************************************************************************
**** ****
**** void FAR PASCAL Windows_Interrupt(cElapsed) ****
**** ****
**** DWORD cElapsed ****
**** ****
**** Synopsis: ****
**** ****
**** Allows Windows to access other applications that may be running ****
**** A call to PeekMessage accomplishes this, and we process all calling ****
**** window messages. Will only call PeekMessage if _cElapsed_ time ****
**** has passed since the last call to Windows_Interrupt. ****
**** ****
*****************************************************************************/
public void FAR PASCAL
Windows_Interrupt(cElapsed)
DWORD cElapsed;
{
static cTick = 0; /* number of ticks since first called */
MSG msg; /* Windows message structure */
if ((GetTickCount() - cTick) > cElapsed)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
cTick = GetTickCount();
}
}
/*****************************************************************************
**** ****
**** LPSTR FAR PASCAL WinMem_Malloc(wFlags, wBytes) ****
**** ****
**** WORD wFlags ****
**** WORD wBytes ****
**** ****
**** Synopsis: ****
**** ****
**** Allocates _wBytes_ bytes of memory in a dynamically allocated ****
**** segment. _wBytes_ cannot be greater than SEGLENGTH. wFlags can be ****
**** any of the local memory allocation flags defined in the Windows ****
**** Programmer's Reference, usually LMEM_MOVEABLE. ****
**** Returns a valid pointer if successful, NULL if not. ****
**** ****
**** ****
*****************************************************************************/
public LPSTR FAR PASCAL WinMem_Malloc(WORD wFlags, WORD wBytes)
{
int offset;
int i,j;
BOOL found;
HANDLE hmem;
LPSTR lp;
PSTR p;
LONG lSize;
WORD wSeg;
static BOOL bFirst = TRUE;
if (bFirst)
{
bFirst = FALSE;
WinMem_Init();
}
if ((long)wBytes > (SEGLENGTH - 16)) return(NULL);
for (i = 0; i < NUMSEGS; i++)
{
if (seg[i] == NULL)
{
/**** Get global segment, initialize local heap ****/
hmem = GlobalAlloc(GMEM_MOVEABLE, SEGLENGTH);
if (!hmem) return(NULL);
lp = GlobalWire(hmem);
wSeg = HIWORD(lp);
seg[i] = hmem;
lSize = GlobalSize(hmem) - 16; /*
* reserve 16 bytes for local
* heap initialization
*/
if (lSize > (SEGLENGTH - 16)) lSize = SEGLENGTH - 16;
if (!LocalInit(wSeg,0,lSize)) return(NULL);
freemem[i] = (WORD) lSize;
GlobalUnlock(hmem); /* from LocalInit */
GlobalUnWire(hmem);
}
if (freemem[i] > wBytes)
{
lp = GlobalWire(seg[i]);
if (!lp) return(NULL);
wSeg = HIWORD(lp);
asm { push ds
mov ax, wSeg
mov ds, ax
}
hmem = LocalAlloc(wFlags, wBytes);
asm { pop ds
}
GlobalUnWire(seg[i]);
if (hmem)
{
j = i;
break;
}
}
}
if (!hmem) return(NULL);
lp = GlobalWire (seg[j]); /*
* move to low memory, will be
* unwired in WinMem_Free
*/
if (!lp) return(NULL);
wSeg = HIWORD(lp);
asm { push ds
mov ax, wSeg
mov ds, ax
}
i = LocalSize(hmem);
p = LocalLock (hmem);
asm { pop ds
}
freemem[j] -= i;
if (!p) return(NULL);
else return (LPSTR)MAKELONG (p, wSeg);
}
/*****************************************************************************
**** ****
**** LPSTR FAR PASCAL WinMem_Free(lpfree) ****
**** ****
**** LPSTR lpfree ****
**** ****
**** Synopsis: ****
**** ****
**** Frees the block of memory in a dynamically allocated segment ****
**** pointed to by _lpFree_. ****
**** Returns NULL if successful, lpfree if not ****
**** ****
**** ****
*****************************************************************************/
public LPSTR FAR PASCAL WinMem_Free(LPSTR lpfree)
{
HANDLE hmem, hseg;
LPSTR lp;
WORD wSeg;
int i,j;
wSeg = HIWORD(lpfree);
hseg = GlobalHandle(wSeg);
j = -1;
for (i = 0; i < NUMSEGS; i++)
{
if (seg[i] == hseg)
{
j = i;
break;
}
}
if (j == -1) return(lpfree);
lp = GlobalWire(hseg);
if (!lp) goto FAIL;
asm { push ds
mov ax, wSeg
mov ds, ax
}
hmem = LocalHandle(LOWORD(lpfree));
if (!hmem)
{
asm { pop ds
}
goto FAIL;
}
i = LocalSize(hmem);
if (!LocalUnlock (hmem))
{
hmem = LocalFree(hmem); /*returns NULL if successful*/
if (hmem)
{
asm { pop ds
}
goto FAIL;
}
}
else
{
asm { pop ds
}
goto FAIL;
}
asm { pop ds
}
freemem[j] += i;
GlobalUnWire(hseg);
if ((GlobalUnWire(hseg)) && (freemem[j] == (SEGLENGTH - 16))) /* TRUE if lock count at 0 */
{
GlobalFree(hseg);
seg[j] = NULL;
freemem[j] = 0;
}
return(NULL);
FAIL:
return(lpfree);
}
/*****************************************************************************
*****************************************************************************
**** ****
**** Private Routines ****
**** ****
*****************************************************************************
*****************************************************************************/
/*
* void FAR PASCAL WinMem_Init()
*
* internal routine to initialize memory manager
* called automatically as needed
*/
private void NEAR PASCAL WinMem_Init()
{
int i;
for (i = 0; i < NUMSEGS; i++)
{
seg[i] = NULL;
freemem[i] = 0;
}
}
/*
* This routine recursively creates a random tree in the previously allocated
* space starting at _tree_. It returns a pointer giving the next available
* space for other calls.
*/
private LPATREE NEAR PASCAL
build_tree(connection,complemented,start,end,tree)
LPINT connection;
char far *complemented;
int start;
int end;
LPATREE tree;
{
int mid;
LPATREE next_node;
LPATREE right_descendant;
/* Allocate this node */
tree -> function = RANDOM(4);
tree -> sig_left = UNEVALUATED;
tree -> sig_right = UNEVALUATED;
if (!LOWORD(tree)) /* this node starts a segment */
tree -> seg_flag = TRUE;
else
tree -> seg_flag = FALSE;
switch (tree -> function)
{
case AND:
tree -> cnt_10 = BELOWMID;
tree -> cnt_01 = BELOWMID;
break;
case RIGHT:
tree -> cnt_10 = BELOWMID;
tree -> cnt_01 = ABOVEMID;
break;
case LEFT:
tree -> cnt_10 = ABOVEMID;
tree -> cnt_01 = BELOWMID;
break;
case OR:
tree -> cnt_10 = ABOVEMID;
tree -> cnt_01 = ABOVEMID;
break;
}
/* Are we at a leaf ?? */
if (end - start < 3)
{
/* This is a leaf */
if (end - start == 1)
{
tree -> /*left*/ leaf_flag = LEFTLEAF;
tree -> /*right*/ leaf_flag |= RIGHTLEAF;
tree -> /*left*/ cmp_flag = (LEFTLEAF & complemented[start]);
tree -> left.leaf = connection[start];
tree -> /*right*/ cmp_flag |= (RIGHTLEAF & complemented[end]);
tree -> right.leaf = connection[end];
next_node = tree + 1;
}
else
{
assert(end - start == 2);
tree -> /*left*/ leaf_flag = LEFTLEAF;
tree -> /*right*/ leaf_flag &= ~(RIGHTLEAF);
tree -> /*left*/ cmp_flag = (LEFTLEAF & complemented[start]);
tree -> left.leaf = connection[start];
tree -> right.child = tree + 1;
/* segment boundary check */
if (!LOWORD(tree -> right.child)) /* crossed segment bound */
{
DWORD nodes = end - start;
if (nodes >= (SEGLENGTH / sizeof(atree)))
tree -> right.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE, SEGLENGTH));
else
tree -> right.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE, nodes * sizeof(atree)));
MEMCHECK(tree -> right.child);
}
next_node = build_tree(connection,complemented,start+1,end,tree -> right.child);
}
}
else
{
/* This is a not a leaf (ie, a node) */
tree -> leaf_flag = FALSE;
tree -> cmp_flag = FALSE;
/* Create left descendants */
mid = start + ((end - start)/2);
tree -> left.child = tree + 1;
/* segment boundary check */
if (!LOWORD(tree -> left.child)) /* crossed segment bound */
{
DWORD nodes = mid - start;
if (nodes >= (SEGLENGTH / sizeof(atree)))
tree -> left.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE,SEGLENGTH));
else
tree -> left.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE,nodes * sizeof(atree)));
MEMCHECK(tree -> left.child);
}
right_descendant = build_tree(connection,complemented,start,mid,tree -> left.child);
/* Create right descendants and return next available node */
tree -> right.child = right_descendant;
/* segment boundary check */
if (!LOWORD(tree -> right.child)) /* crossed segment bound */
{
DWORD nodes = end - mid;
if (nodes >= (SEGLENGTH / sizeof(atree)))
tree -> right.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE,SEGLENGTH));
else
tree -> right.child = (LPATREE) GlobalWire(GlobalAlloc(
GMEM_MOVEABLE, nodes * sizeof(atree)));
MEMCHECK(tree -> right.child);
}
next_node = build_tree(connection,complemented,mid+1,end,right_descendant);
}
return(next_node);
}
/*
* print_tree routine prints out an atree to the
* file pointed to by _fp_
*/
private void NEAR PASCAL
print_tree(tree,indent,verbosity,hOut)
LPATREE tree;
int indent;
int verbosity;
int hOut;
{
int i;
char szBuffer[80];
if (RIGHTLEAF & (tree -> leaf_flag))
{
for (i = 0; i < indent + 3; i++)
{
Printf(" ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
if (RIGHTLEAF & (tree -> cmp_flag))
{
Printf("Leaf : !%d ",tree -> right.leaf);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
else
{
Printf("Leaf : %d ",tree -> right.leaf);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
VERBOSE(1,Printf(",",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
PRINTBOOL(tree -> sig_right);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer)));
Printf("\r\n",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
else
{
print_tree(tree -> right.child,indent + 3,verbosity,hOut);
}
for (i = 0; i < indent; i++)
{
Printf(" ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
switch (tree -> function)
{
case AND:
Printf("AND ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
break;
case RIGHT:
Printf("RIGHT ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
break;
case LEFT:
Printf("LEFT ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
break;
case OR:
Printf("OR ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
break;
}
VERBOSE(1, Printf("rsp = ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
Printf(",r=",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
PRINTBOOL(tree -> sig_right);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
Printf(",l=",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
PRINTBOOL(tree -> sig_left);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer)));
Printf("\r\n",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
if (LEFTLEAF & (tree -> leaf_flag))
{
for (i = 0; i < indent + 3; i++)
{
Printf(" ",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
if (LEFTLEAF & (tree -> cmp_flag))
{
Printf("Leaf : !%d ",tree -> left.leaf);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
else
{
Printf("Leaf : %d ",tree -> left.leaf);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
VERBOSE(1,Printf(",",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
PRINTBOOL(tree -> sig_left);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer)));
Printf("\r\n",0);
_lwrite(hOut, (LPSTR) szBuffer, lstrlen((LPSTR) szBuffer));
}
else
{
print_tree(tree -> left.child,indent + 3,verbosity, hOut);
}
}
/*
* bool train(tree,vec,result)
*
* LPATREE tree;
* LPBITVEC vec;
* bool result;
*
* This routine is actually responsible for the training of a tree for a
* single input vector and result. If the tree gets the correct result
* before the adaptation step occurs, the routine returns TRUE, otherwise,
* false.
*/
private bool NEAR PASCAL
train(tree,vec,result)
LPATREE tree;
LPBIT_VEC vec;
bool result;
{
bool correct;
/* What does the tree currently think ?*/
correct = (bool)atree_eval(tree,vec) == result;
/* Adapt the tree */
adapt(tree,vec,result);
/* Did the tree get it right ? */
correct = (bool)atree_eval(tree,vec) == result;
/* If not, try again ! */
if (!correct)
{
adapt(tree,vec,result);
}
return(correct);
}
/*
* adapt(tree,vec,result)
*
* LPATREE tree;
* LPBIT_VEC vec;
* bool result;
*
*/
private void NEAR PASCAL
adapt(tree,vec,result)
LPATREE tree;
LPBIT_VEC vec;
bool result;
{
/*
* INCR and DECR implement bounded counters, remembering that TRUE == 1,
* how much should be added to t when t == MAXSET ?
*/
#define INCR(t) t += (t != MAXSET)
#define DECR(t) t -= (t != MINSET)
/* If the left child is unevaluated, evaluate it */
if (tree -> sig_left == UNEVALUATED)
{
LEFTEVAL;
}
/* If the right child is unevaluated, evaluate it */
if (tree -> sig_right == UNEVALUATED)
{
RIGHTEVAL;
}
/* Update the counters if needed */
if (tree -> sig_left != tree -> sig_right)
{
if (tree -> sig_left)
{
if (tree -> sig_left == result)
{
INCR(tree -> cnt_10);
}
else
{
DECR(tree -> cnt_10);
}
}
else
{
assert(tree -> sig_right);
if (tree -> sig_right == result)
{
INCR(tree -> cnt_01);
}
else
{
DECR(tree -> cnt_01);
}
}
/* has the node function changed */
tree -> function = node_function(tree);
}
/* Assign responsibility to the left child */
if (!(LEFTLEAF & (tree -> leaf_flag)))
{
if (tree -> sig_right != result)
{
adapt(tree -> left.child,vec,result);
}
else if ((tree -> function == LEFT) || (tree -> function == RIGHT))
{
adapt(tree -> left.child,vec,result);
}
else
{
if (tree -> sig_right)
{
if (tree -> cnt_01 < ABOVEMID)
{
adapt(tree -> left.child,vec,result);
}
}
else
{
if (tree -> cnt_10 >= ABOVEMID)
{
adapt(tree -> left.child,vec,result);
}
}
}
}
/* Assign responsibility to the right child */
if (!(RIGHTLEAF & (tree -> leaf_flag)))
{
if (tree -> sig_left != result)
{
adapt(tree -> right.child,vec,result);
}
else if ((tree -> function == LEFT) || (tree -> function == RIGHT))
{
adapt(tree -> right.child,vec,result);
}
else
{
if (tree -> sig_left)
{
if (tree -> cnt_10 < ABOVEMID)
{
adapt(tree -> right.child,vec,result);
}
}
else
{
if (tree -> cnt_01 >= ABOVEMID)
{
adapt(tree -> right.child,vec,result);
}
}
}
}
}
private char NEAR PASCAL
node_function(tree)
LPATREE tree;
{
char result;
if (tree -> cnt_10 >= ABOVEMID)
{
if (tree -> cnt_01 >= ABOVEMID)
{
result = OR;
}
else
{
result = LEFT;
}
}
else
{
if (tree -> cnt_01 >= ABOVEMID)
{
result = RIGHT;
}
else
{
result = AND;
}
}
return(result);
}
#pragma warn -rvl
error(s)
char *s;
{
char szBuffer[80];
wsprintf(szBuffer,"Error: %s ", s);
MessageBox(NULL,szBuffer,"ERROR",MB_OK);
exit(0);
}
#pragma warn .rvl